﻿using System.Collections.Generic;
using System.Net.DnsToolkit.Packet;
using System.Net.DnsToolkit.Packet.Records;
using System.Net.DnsToolkit.TestUnit.Helper;
using NUnit.Framework;
using System.Net.DnsToolkit.Packet.Busy;
using System.Net.DnsToolkit.Packet.Busy.Records;

namespace System.Net.DnsToolkit.TestUnit.Serializer
{
    [TestFixture]
    public class FullPacketTest {

        #region FullPackets
        /// <summary>
        /// Domain Name System (query)
        /// Transaction Id: 0x0003
        /// Flags: 0x0100 (Standard query)
        ///    0... .... .... .... = RESPONSE: Message is a query
        ///    .000 0... .... .... = Opcode: Standard query (0)
        ///    .... .0.. .... .... = Authoritative: Server is not an authority for domain
        ///    .... ..0. .... .... = Truncated: Message is not truncated
        ///    .... ...1 .... .... = Recursion desired: Do query recursively
        ///    .... .... 0... .... = Recursion available: No
        ///    .... .... .0.. .... = Z: reserved (0)
        ///    .... .... ..0. .... = Answer authenticated: Answer/authority portion was not authenticated by the server
        ///    .... .... ...0 .... = Non-authenticated data OK: Non-authenticated data is unacceptable
        ///    .... .... .... 0000 = Reply code: No error (0)
        /// Questions: 1
        /// Answer RRs: 0
        /// Authority RRs: 0
        /// Additional RRs: 0
        /// Queries
        ///    www.domn.tl: type A, class In
        ///       Name: www.domn.tl
        ///       Type: A (Host address)
        ///       Class: In (0x0001)
        /// </summary>
        [Test]
        public void TestFullPacket1()
        {

            const string expected = "0003010000010000000000000377777704646F6D6E02746C0000010001";

            var message = new Message {
                Header = new Header {
                    Id = 3,
                    // flags
                    QueryType = QREnum.QUERY,
                    OpCode = OpCodeEnum.StandardQuery,
                    AuthoritativeAnswer = false,
                    Truncation = false,
                    RecursionDesired = true,
                    RecursionAvailable = false,
                    Reserved = false,
                    AnswerAuthenticated = false,
                    NotAuthenticatedAcceptable = false,
                    ResponseCode = RCodeEnum.NoError,
                    // counts
                    QuestionCount = 1,
                    ResourceCount = 0,
                    AnswerCount = 0,
                    AuthorityCount = 0,
                },
                Questions = new List<IQuestion> {
                      new Question {
                              QName = new DomainName {Name = "www.domn.tl."},
                              QType = QTypeEnum.A,
                              QClass = QClassEnum.IN
                      }
                }
            };


            // Message message = PacketHelper.Deserialize(expected);
            string actual = PacketHelper.Write(message, false);
            Assert.AreEqual(expected, actual, "message");

        }

        /// <summary>
        /// Domain Name System (query)
        /// Transaction Id: 0x0003
        /// Flags: 0x0100 (Standard query)
        ///    0... .... .... .... = RESPONSE: Message is a query
        ///    .000 0... .... .... = Opcode: Standard query (0)
        ///    .... .0.. .... .... = Authoritative: Server is not an authority for domain
        ///    .... ..0. .... .... = Truncated: Message is not truncated
        ///    .... ...1 .... .... = Recursion desired: Do query recursively
        ///    .... .... 0... .... = Recursion available: No
        ///    .... .... .0.. .... = Z: reserved (0)
        ///    .... .... ..0. .... = Answer authenticated: Answer/authority portion was not authenticated by the server
        ///    .... .... ...0 .... = Non-authenticated data OK: Non-authenticated data is unacceptable
        ///    .... .... .... 0000 = Reply code: No error (0)
        /// Questions: 1
        /// Answer RRs: 0
        /// Authority RRs: 0
        /// Additional RRs: 0
        /// Queries
        ///    www.domn.tl: type A, class In
        ///       Name: www.domn.tl
        ///       Type: A (Host address)
        ///       Class: In (0x0001)
        /// </summary>
        [Test]
        public void TestFullPacket1A() {

            const string expected = "00030100000100000000000004686F737406646F6D61696E03746C640000010001";

            var message = new Message {
                                                Header = new Header {
                                                                          Id = 3,
                                                                          // flags
                                                                          QueryType = QREnum.QUERY,
                                                                          OpCode = OpCodeEnum.StandardQuery,
                                                                          AuthoritativeAnswer = false,
                                                                          Truncation = false,
                                                                          RecursionDesired = true,
                                                                          RecursionAvailable = false,
                                                                          Reserved = false,
                                                                          AnswerAuthenticated = false,
                                                                          NotAuthenticatedAcceptable = false,
                                                                          ResponseCode = RCodeEnum.NoError,
                                                                          // counts
                                                                          QuestionCount = 1,
                                                                          ResourceCount = 0,
                                                                          AnswerCount = 0,
                                                                          AuthorityCount = 0,
                                                                      },
                                                Questions = new List<IQuestion> {
                                                                                     new Question {
                                                                                                        QName = new DomainName { Name = "host.domain.tld." },
                                                                                                        QType = QTypeEnum.A,
                                                                                                        QClass = QClassEnum.IN
                                                                                                    }
                                                                                 }
                                            };


            // Message message = PacketHelper.Deserialize(expected);
            string actual = PacketHelper.Write(message, false);
            Assert.AreEqual(expected, actual, "message");

        }

        /// <summary>
        /// Domain Name System (query)
        /// Transaction Id: 0x0003
        /// Flags: 0x0100 (Standard query)
        ///    0... .... .... .... = RESPONSE: Message is a query
        ///    .000 0... .... .... = Opcode: Standard query (0)
        ///    .... .0.. .... .... = Authoritative: Server is not an authority for domain
        ///    .... ..0. .... .... = Truncated: Message is not truncated
        ///    .... ...1 .... .... = Recursion desired: Do query recursively
        ///    .... .... 0... .... = Recursion available: No
        ///    .... .... .0.. .... = Z: reserved (0)
        ///    .... .... ..0. .... = Answer authenticated: Answer/authority portion was not authenticated by the server
        ///    .... .... ...0 .... = Non-authenticated data OK: Non-authenticated data is unacceptable
        ///    .... .... .... 0000 = Reply code: No error (0)
        /// Questions: 1
        /// Answer RRs: 0
        /// Authority RRs: 0
        /// Additional RRs: 0
        /// Queries
        ///    www.domn.tl: type A, class In
        ///       Name: www.domn.tl
        ///       Type: A (Host address)
        ///       Class: In (0x0001)
        /// </summary>
        [Test]
        public void TestFullPacket1B() {

            const string expecteds = "00038580000100010001000104686F737406646F6D61696E03746C640000010001C00C0001000100015180000401020304C01100020001000151800002C011C0110001000100015180000401020304";

            var actual = new Message {
                                               Header = new Header {
                                                                         Id = 3,
                                                                         // flags
                                                                         QueryType = QREnum.RESPONSE,
                                                                         OpCode = OpCodeEnum.StandardQuery,
                                                                         AuthoritativeAnswer = true,
                                                                         Truncation = false,
                                                                         RecursionDesired = true,
                                                                         RecursionAvailable = true,
                                                                         Reserved = false,
                                                                         AnswerAuthenticated = false,
                                                                         NotAuthenticatedAcceptable = false,
                                                                         ResponseCode = RCodeEnum.NoError,
                                                                         // counts
                                                                         QuestionCount = 1,
                                                                         ResourceCount = 1,
                                                                         AnswerCount = 1,
                                                                         AuthorityCount = 1,
                                                                     },
                                               Questions = new List<IQuestion> {
                                                                                    new Question {
                                                                                                       QName = new DomainName { Name = "host.domain.tld." },
                                                                                                       QType = QTypeEnum.A,
                                                                                                       QClass = QClassEnum.IN
                                                                                                   }
                                                                                },
                                               Answers = new List<IRR> {
                                                                            new RR {
                                                                                         Name = new DomainName { Name = "host.domain.tld." },
                                                                                         RRType = QTypeEnum.A,
                                                                                         RRClass = QClassEnum.IN,
                                                                                         Ttl = 86400,
                                                                                         RDLength = 4,
                                                                                         RData = new RecordA {
                                                                                                                   Address = IPAddress.Parse("1.2.3.4")
                                                                                                               }
                                                                                     }
                                                                        },
                                               Additionals = new List<IRR> {
                                                                                new RR {
                                                                                             Name = new DomainName { Name = "domain.tld." },
                                                                                             RRType = QTypeEnum.NS,
                                                                                             RRClass = QClassEnum.IN,
                                                                                             Ttl = 86400,
                                                                                             RDLength = 2, // attention à la compression
                                                                                             RData = new RecordNS {
                                                                                                                        NSDNAME = new DomainName { Name = "domain.tld." }
                                                                                                                    }
                                                                                         }
                                                                            },
                                               Authorities = new List<IRR> {
                                                                                new RR {
                                                                                             Name = new DomainName { Name = "domain.tld." },
                                                                                             RRType = QTypeEnum.A,
                                                                                             RRClass = QClassEnum.IN,
                                                                                             Ttl = 86400,
                                                                                             RDLength = 4,
                                                                                             RData = new RecordA {
                                                                                                                       Address = IPAddress.Parse("1.2.3.4")
                                                                                                                   }
                                                                                         }
                                                                            }

                                           };


            // Message message = PacketHelper.Deserialize(expected);
            var expected = PacketHelper.Read(expecteds);

            MessageHelper.DeepCompare(expected, actual);

        }

        /// <summary>
        /// Domain Name System (query)
        /// Transaction Id: 0x0003
        /// Flags: 0x0100 (Standard query)
        ///    0... .... .... .... = RESPONSE: Message is a query
        ///    .000 0... .... .... = Opcode: Standard query (0)
        ///    .... .0.. .... .... = Authoritative: Server is not an authority for domain
        ///    .... ..0. .... .... = Truncated: Message is not truncated
        ///    .... ...1 .... .... = Recursion desired: Do query recursively
        ///    .... .... 0... .... = Recursion available: No
        ///    .... .... .0.. .... = Z: reserved (0)
        ///    .... .... ..0. .... = Answer authenticated: Answer/authority portion was not authenticated by the server
        ///    .... .... ...0 .... = Non-authenticated data OK: Non-authenticated data is unacceptable
        ///    .... .... .... 0000 = Reply code: No error (0)
        /// Questions: 1
        /// Answer RRs: 0
        /// Authority RRs: 0
        /// Additional RRs: 0
        /// Queries
        ///    www.domn.tl: type A, class In
        ///       Name: www.domn.tl
        ///       Type: A (Host address)
        ///       Class: In (0x0001)
        /// </summary>
        [Test]
        public void TestFullPacket1C() {

            const string expecteds = "00030100000100000000000004686F737406646F6D61696E03746C640000010001C00C0001000100015180000401020304C011000200010003F4800002C011C0110001000100015180000401020304";

            var actual = new Message {
                                               Header = new Header {
                                                                         Id = 3,
                                                                         // flags
                                                                         QueryType = QREnum.QUERY,
                                                                         OpCode = OpCodeEnum.StandardQuery,
                                                                         AuthoritativeAnswer = false,
                                                                         Truncation = false,
                                                                         RecursionDesired = true,
                                                                         RecursionAvailable = false,
                                                                         Reserved = false,
                                                                         AnswerAuthenticated = false,
                                                                         NotAuthenticatedAcceptable = false,
                                                                         ResponseCode = RCodeEnum.NoError,
                                                                         // counts
                                                                         QuestionCount = 1,
                                                                         ResourceCount = 0,
                                                                         AnswerCount = 0,
                                                                         AuthorityCount = 0,
                                                                     },
                                               Questions = new List<IQuestion> {
                                                                                    new Question {
                                                                                                       QName = new DomainName { Name = "host.domain.tld." },
                                                                                                       QType = QTypeEnum.A,
                                                                                                       QClass = QClassEnum.IN
                                                                                                   }
                                                                                },
                                               Answers = new List<IRR>(),
                                               Additionals = new List<IRR>(),
                                               Authorities = new List<IRR>()

                                           };


            // Message message = PacketHelper.Deserialize(expected);
            var expected = PacketHelper.Read(expecteds);

            MessageHelper.DeepCompare(expected, actual);

        }

        


        /// <summary>
        /// Domain Name System (response)
        /// Time: 0.000733000 seconds
        /// Transaction Id: 0x0004
        /// Flags: 0x8180 (Standard query response, No error)
        ///    1... .... .... .... = RESPONSE: Message is a response
        ///    .000 0... .... .... = Opcode: Standard query (0)
        ///    .... .0.. .... .... = Authoritative: Server is not an authority for domain
        ///    .... ..0. .... .... = Truncated: Message is not truncated
        ///    .... ...1 .... .... = Recursion desired: Do query recursively
        ///    .... .... 1... .... = Recursion available: Server can do recursive queries
        ///    .... .... .0.. .... = Z: reserved (0)
        ///    .... .... ..0. .... = Answer authenticated: Answer/authority portion was not authenticated by the server
        ///    .... .... .... 0000 = Reply code: No error (0)
        /// Questions: 1
        /// Answer RRs: 1
        /// Authority RRs: 2
        /// Additional RRs: 2
        ///
        /// Queries
        ///    www.domn.tl: type A, class In
        ///       Name: www.domn.tl
        ///       Type: A (Host address)
        ///       Class: In (0x0001)
        ///
        /// Answers
        ///    www.domn.tl: type A, class In, addr 1.2.3.4
        ///       Name: www.domn.tl
        ///       Type: A (Host address)
        ///       Class: In (0x0001)
        ///       Time to live: 23 hours, 32 minutes, 32 seconds
        ///       Data length: 4
        ///       Addr: 1.2.3.4
        ///
        /// Authoritative nameservers
        ///    domn.tl: type NS, class In, ns ns01.prv.tl
        ///       Name: domn.tl
        ///       Type: NS (Authoritative name server)
        ///       Class: In (0x0001)
        ///       Time to live: 23 hours, 32 minutes, 32 seconds
        ///       Data length: 11
        ///       Name server: ns01.prv.tl
        ///
        ///    domn.tl: type NS, class In, ns ns02.prv.tl
        ///       Name: domn.tl
        ///       Type: NS (Authoritative name server)
        ///       Class: In (0x0001)
        ///       Time to live: 23 hours, 32 minutes, 32 seconds
        ///       Data length: 11
        ///       Name server: ns02.prv.tl
        ///
        /// Additional records
        ///    ns01.prv.tl: type A, class In, addr 1.2.10.15
        ///       Name: ns01.prv.tl
        ///       Type: A (Host address)
        ///       Class: In (0x0001)
        ///       Time to live: 23 hours, 34 minutes, 41 seconds
        ///       Data length: 4
        ///       Addr: 1.2.10.15
        ///
        ///    ns01.prv.tl: type A, class In, addr 1.2.10.161
        ///       Name: ns01.prv.tl
        ///       Type: A (Host address)
        ///       Class: In (0x0001)
        ///       Time to live: 23 hours, 34 minutes, 41 seconds
        ///       Data length: 4
        ///       Addr: 1.2.10.161
        ///
        /// </summary>
        [Test]
        public void TestFullPacket2() {

            const string expecteds = "0003818000010001000200020377777704646F6D6E02746C0000010001C00C0001000100015180000401020304C0100002000100015180000B046E73303103707276C015C01000020001000151800007046E733032C03EC0390001000100014E7B0004D4930A0FC0500001000100014AF60004D4930AA1";

            var expected = PacketHelper.Read(expecteds);
            string actuals = PacketHelper.Write(expected);
            var actual = PacketHelper.Read(actuals);

            MessageHelper.DeepCompare(expected, actual);

            Assert.AreEqual(1, expected.Questions.Count);
            Assert.AreEqual(1, expected.Answers.Count);
            Assert.AreEqual(2, expected.Additionals.Count);
            Assert.AreEqual(2, expected.Authorities.Count);



        }
        /// <summary>
        /// Domain Name System (response)
        /// Time: 0.000733000 seconds
        /// Transaction Id: 0x0003
        /// Flags: 0x8180 (Standard query response, No error)
        ///    1... .... .... .... = RESPONSE: Message is a response
        ///    .000 0... .... .... = Opcode: Standard query (0)
        ///    .... .0.. .... .... = Authoritative: Server is not an authority for domain
        ///    .... ..0. .... .... = Truncated: Message is not truncated
        ///    .... ...1 .... .... = Recursion desired: Do query recursively
        ///    .... .... 1... .... = Recursion available: Server can do recursive queries
        ///    .... .... .0.. .... = Z: reserved (0)
        ///    .... .... ..0. .... = Answer authenticated: Answer/authority portion was not authenticated by the server
        ///    .... .... .... 0000 = Reply code: No error (0)
        /// Questions: 1
        /// Answer RRs: 1
        /// Authority RRs: 2
        /// Additional RRs: 2
        ///
        /// Queries
        ///    www.domn.tl: type A, class In
        ///       Name: www.domn.tl
        ///       Type: A (Host address)
        ///       Class: In (0x0001)
        ///
        /// Answers
        ///    www.domn.tl: type A, class In, addr 1.2.3.4
        ///       Name: www.domn.tl
        ///       Type: A (Host address)
        ///       Class: In (0x0001)
        ///       Time to live: 23 hours, 32 minutes, 32 seconds
        ///       Data length: 4
        ///       Addr: 1.2.3.4
        ///
        /// </summary>
        [Test]
        public void TestFullPacket3() {

            const string expected = "0003818000010001000000000377777704646F6D6E02746C00000100010377777704646F6D6E02746C000001000100015180000401020304";
            var message = PacketHelper.Read(expected);
            string actual = PacketHelper.Write(message, false);

            Assert.AreEqual(expected, actual, "message");


        }

        #endregion

        #region MX

        [Test]
        public void TestQueryMX1() {
            const string pkt = "00020100000100000000000004646f6d6e02746c00000f0001";

            var expected = new Message {
                                                 Header = new Header {
                                                                           Id = 2,
                                                                           // flags
                                                                           QueryType = QREnum.QUERY,
                                                                           OpCode = OpCodeEnum.StandardQuery,
                                                                           AuthoritativeAnswer = false,
                                                                           Truncation = false,
                                                                           RecursionDesired = true,
                                                                           RecursionAvailable = false,
                                                                           Reserved = false,
                                                                           AnswerAuthenticated = false,
                                                                           NotAuthenticatedAcceptable = false,
                                                                           ResponseCode = RCodeEnum.NoError,
                                                                           // counts
                                                                           QuestionCount = 1,
                                                                           ResourceCount = 0,
                                                                           AnswerCount = 0,
                                                                           AuthorityCount = 0,
                                                                       },
                                                 Questions = new List<IQuestion> {
                                                                                      new Question {
                                                                                                         QName = new DomainName { Name = "domn.tl." },
                                                                                                         QType = QTypeEnum.MX,
                                                                                                         QClass = QClassEnum.IN
                                                                                                     }
                                                                                  }
                                             };


            var actual = PacketHelper.Read(pkt);
            MessageHelper.DeepCompare(expected, actual);

            string rebuilt = PacketHelper.Write(actual).ToLower();
            Assert.AreEqual(pkt, rebuilt, "packet");

            var actual2 = PacketHelper.Read(rebuilt);
            MessageHelper.DeepCompare(expected, actual2);
        }


        [Test]
        public void TestResponseMX1() {
            const string pkt = "00028180000100010000000104646f6d6e02746c00000f0001c00c000f00010001518000090000046d61696cc00cc0270001000100015180000401020304";

            var expected = new Message {
                                                 Header = new Header {
                                                                           Id = 2,
                                                                           // flags
                                                                           QueryType = QREnum.RESPONSE,
                                                                           OpCode = OpCodeEnum.StandardQuery,
                                                                           AuthoritativeAnswer = false,
                                                                           Truncation = false,
                                                                           RecursionDesired = true,
                                                                           RecursionAvailable = true,
                                                                           Reserved = false,
                                                                           AnswerAuthenticated = false,
                                                                           NotAuthenticatedAcceptable = false,
                                                                           ResponseCode = RCodeEnum.NoError,
                                                                           // counts
                                                                           QuestionCount = 1,
                                                                           ResourceCount = 0,
                                                                           AnswerCount = 1,
                                                                           AuthorityCount = 1,
                                                                       },
                                                 Questions = new List<IQuestion> {
                                                                                      new Question {
                                                                                                         QName = new DomainName { Name = "domn.tl." },
                                                                                                         QType = QTypeEnum.MX,
                                                                                                         QClass = QClassEnum.IN
                                                                                                     }
                                                                                  },
                                                 Answers = new List<IRR> {
                                                                              new RR {
                                                                                           Name = new DomainName { Name = "domn.tl." },
                                                                                           RRType = QTypeEnum.MX,
                                                                                           RRClass = QClassEnum.IN,
                                                                                           Ttl = 86400,
                                                                                           RDLength = 9,
                                                                                           RData = new RecordMX {
                                                                                                                      PREFERENCE = 0,
                                                                                                                      EXCHANGE = new DomainName { Name = "mail.domn.tl."}
                                                                                                                  }
                                                                                       }
                                                                          },
                                                 Authorities = new List<IRR> {
                                                                                  new RR {
                                                                                               Name = new DomainName { Name = "mail.domn.tl." },
                                                                                               RRType = QTypeEnum.A,
                                                                                               RRClass = QClassEnum.IN,
                                                                                               Ttl = 86400,
                                                                                               RDLength = 4,
                                                                                               RData = new RecordA {
                                                                                                                         Address = IPAddress.Parse("1.2.3.4")
                                                                                                                     }
                                                                                           }
                                                                              }
                                             };


            var actual = PacketHelper.Read(pkt);
            MessageHelper.DeepCompare(expected, actual);

            string rebuilt = PacketHelper.Write(actual).ToLower();
            Assert.AreEqual(pkt, rebuilt, "packet");

            var actual2 = PacketHelper.Read(rebuilt);
            MessageHelper.DeepCompare(expected, actual2);
        }



        #endregion

        #region PTR

        [Test]
        public void TestQueryPTR1() {
            const string pkt = "0003010000010000000000000331353102343702383302383007696e2d61646472046172706100000c0001";

            var expected = new Message {
                                                 Header = new Header {
                                                                           Id = 3,
                                                                           // flags
                                                                           QueryType = QREnum.QUERY,
                                                                           OpCode = OpCodeEnum.StandardQuery,
                                                                           AuthoritativeAnswer = false,
                                                                           Truncation = false,
                                                                           RecursionDesired = true,
                                                                           RecursionAvailable = false,
                                                                           Reserved = false,
                                                                           AnswerAuthenticated = false,
                                                                           NotAuthenticatedAcceptable = false,
                                                                           ResponseCode = RCodeEnum.NoError,
                                                                           // counts
                                                                           QuestionCount = 1,
                                                                           ResourceCount = 0,
                                                                           AnswerCount = 0,
                                                                           AuthorityCount = 0,
                                                                       },
                                                 Questions = new List<IQuestion> {
                                                                                      new Question {
                                                                                                         QName = new DomainName { Name = "151.47.83.80.in-addr.arpa." },
                                                                                                         QType = QTypeEnum.PTR,
                                                                                                         QClass = QClassEnum.IN
                                                                                                     }
                                                                                  }
                                             };

            var actual = PacketHelper.Read(pkt);
            MessageHelper.DeepCompare(expected, actual);

            string rebuilt = PacketHelper.Write(actual).ToLower();
            Assert.AreEqual(pkt, rebuilt, "packet");

            var actual2 = PacketHelper.Read(rebuilt);
            MessageHelper.DeepCompare(expected, actual2);
        }


        [Test]
        public void TestResponsePTR1() {
            const string pkt = "0003818000010001000000000331353102343702383302383007696e2d61646472046172706100000c0001c00c000c000100015180000e046d61696c04646f6d6e02746c00";

            var expected = new Message {
                                                 Header = new Header {
                                                                           Id = 3,
                                                                           // flags
                                                                           QueryType = QREnum.RESPONSE,
                                                                           OpCode = OpCodeEnum.StandardQuery,
                                                                           AuthoritativeAnswer = false,
                                                                           Truncation = false,
                                                                           RecursionDesired = true,
                                                                           RecursionAvailable = true,
                                                                           Reserved = false,
                                                                           AnswerAuthenticated = false,
                                                                           NotAuthenticatedAcceptable = false,
                                                                           ResponseCode = RCodeEnum.NoError,
                                                                           // counts
                                                                           QuestionCount = 1,
                                                                           ResourceCount = 0,
                                                                           AnswerCount = 1,
                                                                           AuthorityCount = 0,
                                                                       },
                                                 Questions = new List<IQuestion> {
                                                                                      new Question {
                                                                                                         QName = new DomainName { Name = "151.47.83.80.in-addr.arpa." },
                                                                                                         QType = QTypeEnum.PTR,
                                                                                                         QClass = QClassEnum.IN
                                                                                                     }
                                                                                  },
                                                 Answers = new List<IRR> {
                                                                              new RR {
                                                                                           Name = new DomainName { Name = "151.47.83.80.in-addr.arpa." },
                                                                                           RRType = QTypeEnum.PTR,
                                                                                           RRClass = QClassEnum.IN,
                                                                                           Ttl = 86400,
                                                                                           RDLength = 14,
                                                                                           RData = new RecordPTR {
                                                                                                                       PTRDNAME = new DomainName { Name = "mail.domn.tl." }
                                                                                                                   }
                                                                                       }
                                                                          }
                                             };


            var actual = PacketHelper.Read(pkt);
            MessageHelper.DeepCompare(expected, actual);

            string rebuilt = PacketHelper.Write(actual).ToLower();
            Assert.AreEqual(pkt, rebuilt, "packet");

            var actual2 = PacketHelper.Read(rebuilt);
            MessageHelper.DeepCompare(expected, actual2);
        }



        
        #endregion

        #region SOA

        [Test]
        public void TestQuerySOA1() {
            const string pkt = "00040100000100000000000004646f6d6e02746c0000060001";

            var expected = new Message {
                                                 Header = new Header {
                                                                           Id = 4,
                                                                           // flags
                                                                           QueryType = QREnum.QUERY,
                                                                           OpCode = OpCodeEnum.StandardQuery,
                                                                           AuthoritativeAnswer = false,
                                                                           Truncation = false,
                                                                           RecursionDesired = true,
                                                                           RecursionAvailable = false,
                                                                           Reserved = false,
                                                                           AnswerAuthenticated = false,
                                                                           NotAuthenticatedAcceptable = false,
                                                                           ResponseCode = RCodeEnum.NoError,
                                                                           // counts
                                                                           QuestionCount = 1,
                                                                           ResourceCount = 0,
                                                                           AnswerCount = 0,
                                                                           AuthorityCount = 0,
                                                                       },
                                                 Questions = new List<IQuestion> {
                                                                                      new Question {
                                                                                                         QName = new DomainName { Name = "domn.tl."},
                                                                                                         QType = QTypeEnum.SOA,
                                                                                                         QClass = QClassEnum.IN
                                                                                                     }
                                                                                  }
                                             };


            var actual = PacketHelper.Read(pkt);
            MessageHelper.DeepCompare(expected, actual);

            string rebuilt = PacketHelper.Write(actual).ToLower();
            Assert.AreEqual(pkt, rebuilt, "packet");

            var actual2 = PacketHelper.Read(rebuilt);
            MessageHelper.DeepCompare(expected, actual2);
        }


        [Test]
        public void TestResponseSOA1() {
            const string pkt = "00048180000100010000000104646f6d6e02746c0000060001c00c000600010001517f002b046e73303103707276c01109646e736d6173746572c02a77c07a9b0001518000001c2000093a8000015180c02500010001000150a3000401020a0f";

            var expected = new Message {
                Header = new Header {
                    Id = 4,
                    // flags
                    QueryType = QREnum.RESPONSE,
                    OpCode = OpCodeEnum.StandardQuery,
                    AuthoritativeAnswer = false,
                    Truncation = false,
                    RecursionDesired = true,
                    RecursionAvailable = true,
                    Reserved = false,
                    AnswerAuthenticated = false,
                    NotAuthenticatedAcceptable = false,
                    ResponseCode = RCodeEnum.NoError,
                    // counts
                    QuestionCount = 1,
                    ResourceCount = 0,
                    AnswerCount = 1,
                    AuthorityCount = 1,
                },
                Questions = new List<IQuestion> {
                    new Question {
                         QName = new DomainName { Name = "domn.tl."},
                         QType = QTypeEnum.SOA,
                         QClass = QClassEnum.IN
                    }
                },
                Answers = new List<IRR> {
                    new RR {
                       Name = new DomainName { Name = "domn.tl."},
                       RRType = QTypeEnum.SOA,
                       RRClass = QClassEnum.IN,
                       Ttl = 86399,
                       RDLength = 43,
                       RData = new RecordSOA {
                           MNAME = new DomainName { Name = "ns01.prv.tl."},
                           RNAME = new DomainName { Name = "dnsmaster.prv.tl."},
                           SERIAL = 2009103003,
                           EXPIRE = 604800,
                           MINIMUM = 86400,
                           REFRESH = 86400,
                           RETRY = 7200
                       }
                   }
                },
                Authorities = new List<IRR> {
                    new RR {
                        Name = new DomainName { Name = "ns01.prv.tl."},
                        RRType = QTypeEnum.A,
                        RRClass = QClassEnum.IN,
                        Ttl = 86179,
                        RDLength = 4,
                        RData = new RecordA {
                            Address = IPAddress.Parse("1.2.10.15")
                        }
                    }
                }
            };

            var actual = PacketHelper.Read(pkt);
            MessageHelper.DeepCompare(expected, actual);

            string rebuilt = PacketHelper.Write(actual).ToLower();
            Assert.AreEqual(pkt, rebuilt, "packet");

            var actual2 = PacketHelper.Read(rebuilt);
            MessageHelper.DeepCompare(expected, actual2);



        }



        
        #endregion


    }
}